import re
import os
import sys

def extract_events(file_path):
    """Extract all public struct names from the given file.
    Args:
        file_path (str): Path to the file to parse
    Returns:
        list: List of struct names found
    """
    events = []

    try:
        with open(file_path, 'r') as f:
            content = f.read()

            # Find all public struct declarations using regex
            # Pattern matches: public struct StructName {
            matches = re.finditer(r'public\s+class\s+(\w+)\s*<:\s*InteractionEvent\s*\{ // Return: (\w+)', content)

            for match in matches:
                struct_name = match.group(1).strip()
                return_type = match.group(2).strip()
                events.append((struct_name, return_type))

    except FileNotFoundError:
        print(f"Error: File not found - {file_path}")
    except Exception as e:
        print(f"Error reading file: {e}")

    if not events:
        print("No event names found in the input file.")
        sys.exit(1)

    print(f"Found event names: {', '.join([name for name, _ in events])}")

    return events

event_handler_manager_code_header = '''
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
 */
//-----------------------------------------------
// This file is generated by gen.py
// Never modify it directly
//-----------------------------------------------
package magic.interaction

import magic.core.interaction.*
import magic.core.tool.{ToolRequest, ToolResponse}
import magic.core.model.{ChatRequest, ChatResponse}
import magic.utils.randomString

import std.collection.ArrayList
'''

event_handler_manager_header = """
public class EventHandlerManager {
    protected static let CLASS_NAME = "event-handler-manager"

    public EventHandlerManager(
        private let name!: String = randomString(size: 8)
    ) { }


    private static var _global: Option<EventHandlerManager> = None
    public static prop global: EventHandlerManager {
        get() {
            if (let Some(v) <- _global) {
                return v
            } else {
                let v = EventHandlerManager(name: "Global event manager")
                _global = v
                return v
            }
        }
    }
"""

def generate_event_handler_manager(events):
    """Generate the EventHandlerManager code for the given struct names.
    Args:
        events (list): List of struct names to generate handlers for
    Returns:
        str: The generated code
    """
    code = [event_handler_manager_code_header]

    # Generate type aliases for each event handler first
    for struct_name, return_type in events:
        code.append(f"public type {struct_name}EventHandler = ({struct_name}) -> EventResponse<{return_type}>")

    code.append(event_handler_manager_header)

    # Generate private fields and methods for each struct
    for struct_name, return_type in events:
        handler_type = f"{struct_name}EventHandler"
        list_field = f"{struct_name[0].lower()}{struct_name[1:]}EventHandlers"

        # Add field
        code.append(f"    // Handler for {struct_name} events")
        code.append(f"    private let {list_field} = ArrayList<{handler_type}>()")
        code.append("")

        # Add addHandler method
        code.append(f"    public func addHandler(handler: {handler_type}): Unit {{")
        code.append(f"        this.{list_field}.add(handler)")
        code.append("    }")
        code.append("")

        # Add handle method
        code.append(f"    protected func handle(evt: {struct_name}): EventResponse<{return_type}> {{")
        code.append(f"        for (handler in this.{list_field}) {{")
        code.append("            match (handler(evt)) {")
        code.append("                case Continue => ()")
        code.append("                case Continue(v) => return Continue(v)")
        code.append("                case Terminate(v) => return Terminate(v)")
        code.append("            }")
        code.append("        }")
        code.append("        return Continue")
        code.append("    }")
        code.append("")

    # Generate the merge method
    code.append(f"    protected func merge(another: EventHandlerManager): Unit {{")
    for struct_name, return_type in events:
        handler_type = f"{struct_name}EventHandler"
        list_field = f"{struct_name[0].lower()}{struct_name[1:]}EventHandlers"
        code.append(f"        this.{list_field}.add(all: another.{list_field})")

    code.append("    }")

    code.append("}")

    return '\n'.join(code)

event_stream_visitor_code_header = '''
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
 */
//-----------------------------------------------
// This file is generated by gen.py
// Never modify it directly
//-----------------------------------------------
package magic.interaction

import magic.core.interaction.*

'''

def generate_event_stream_visitor(events):
    """Generate the EventHandlerManager code for the given struct names.
    Args:
        events (list): List of struct names to generate handlers for
    Returns:
        str: The generated code
    """
    code = [event_stream_visitor_code_header]

    code.append("public abstract class EventStreamVisitor {")
    code.append("    public EventStreamVisitor(")
    code.append("        private let events: EventStream")
    code.append("    ) { }")

    code.append("")
    code.append("    public func start(): Unit {")
    code.append("        for (event in this.events) {")
    code.append("            this.onEvent(event)")
    code.append("        }")
    code.append("    }")
    code.append("")

    # Generate the merge method
    code.append("    private func onEvent(event: InteractionEvent): Unit {")
    code.append("        match (event.kind) {")
    for event_name, return_type in events:
        event_kind = event_name.replace("Event", "")

        code.append(f"           case EventKind.{event_kind} => ")
        code.append(f"                this.on((event as {event_name}).getOrThrow())")
    code.append("           case EventKind.Sentinel => throw UnsupportedException('Unreachable')")
    code.append("        }")
    code.append("    }")

    # Generate on methods for each event
    for event_name, return_type in events:
        code.append(f"    open public func on(event: {event_name}): Unit {{ }}")
        code.append("")

    code.append("}")

    return '\n'.join(code)

def write_file(output_path, content):
    """Write the generated content to the output file.

    Args:
        output_path (str): Path to the output file
        content (str): Content to write
    """
    try:
        with open(output_path, 'w') as f:
            f.write(content)
        print(f"Successfully generated {output_path}")
    except Exception as e:
        print(f"Error writing to file: {e}")

def main():
    # Input and output file paths
    input_file = "./events.cj"

    # Extract struct names
    events = extract_events(input_file)

    # Generate handler code
    code = generate_event_handler_manager(events)
    # Write to output file
    write_file("./event_handler_manager.cj", code)

    # Generate event visitor code
    code = generate_event_stream_visitor(events)
    # Write to output file
    write_file("./event_stream_visitor.cj", code)

if __name__ == "__main__":
    main()
